
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Reflection;
using System.Text;
using Microsoft.Vsa;

using Swaf;
using Swaf.Logging;
using Swaf.Resource;

namespace Swaf.Script
{
	/// <summary>
	/// Summary description for VsaScriptEnvironment.
	/// </summary>
	public class VsaScriptEnvironment : IScriptEnvironment, IVsaSite
	{
		protected IVsaEngine m_engine;
		protected IVsaCodeItem m_scriptCode;

		public VsaScriptEnvironment(string scriptLanguage)
		{
			IClassFactory scriptFactory = Application.currentApp.factories["NetScriptLanguages"];
            IResourceManager resMgr = Application.globalApp.resMgr;
			if(scriptFactory != null)
			{
				m_engine = (IVsaEngine)scriptFactory.createFromNickName(scriptLanguage, true);
				m_engine.RootMoniker = "com.Swafdev://" + scriptLanguage;
				m_engine.Site = this;
				m_engine.InitNew();
				m_engine.RootNamespace = "Swaf";
				m_engine.Name = "Swaf";
				m_engine.SetOption("CLSCompliant", true);

				//Check for assemblies to reference
				NetScriptingConfigManager configMgr = (NetScriptingConfigManager)Application.currentApp.appData["sysObjs-NetScriptingConfig"];
				if(configMgr != null)
				{
					IApplication app = Application.currentApp;
					bool usingOneAssembly = !Cmn.IsEmpty(app.resMgr.getMacro("RootLoadAssembly"));
					bool regOneAssembly = false;
					foreach(string assemblyName in configMgr.AssemblyReferences)
					{
						string name = null;
						if (usingOneAssembly && assemblyName.StartsWith("$ScriptAssemblyRefLocation$"))
						{
							if (!regOneAssembly)
							{
								name = resMgr.resolve("$RootLoadAssembly$.exe");
								regOneAssembly = true;
							}
							else
								continue;
						}
						else
							name = resMgr.resolve(assemblyName);
                        if (name.ToLower().StartsWith("file://"))
                            name = name.Substring(7);
                        IVsaReferenceItem i = (IVsaReferenceItem)m_engine.Items.CreateItem(name, Microsoft.Vsa.VsaItemType.Reference, Microsoft.Vsa.VsaItemFlag.None);
                        i.AssemblyName = name;
					}
				}
				else
					Application.currentApp.Log.println(Application.DEFAULT_FRAMEWORK_LOG_LEVEL,"Unable to locate NetScriptingConfigManager in Application.currentApp.appData['sysObjs-NetScriptingConfig'].  The system may not be configured appropriately");

				//i = (IVsaReferenceItem)m_engine.Items.CreateItem("mscorlib.dll", Microsoft.Vsa.VsaItemType.Reference, Microsoft.Vsa.VsaItemFlag.None);
				//i.AssemblyName = "mscorlib.dll";

				m_scriptCode = (IVsaCodeItem)m_engine.Items.CreateItem("scriptcode", Microsoft.Vsa.VsaItemType.Code, Microsoft.Vsa.VsaItemFlag.Module);

				if(configMgr != null)
				{
					StringBuilder buff = new StringBuilder();
					foreach(string importName in configMgr.PackageImports)
						buff.Append("import ").Append(resMgr.resolve(importName)).Append(";\n");
					m_scriptCode.AppendSourceText(buff.ToString());
				}
				((IAppManagement)Application.globalApp).OnAppShutdown += new AppShutdownRequest(VsaScriptEnvironment_OnAppShutdown);
			}
		}

		void VsaScriptEnvironment_OnAppShutdown(IApplication app)
		{
			if (m_engine != null)
				m_engine.Close();
		}
		#region IScriptEnvironment Members

		public void completeInitialization()
		{
			m_engine.Compile();
			m_engine.Run();
		}

		public void loadScript(string name, string script)
		{
			//TODO: Name is used to logically identify the code block if something errors in debug.  Figure out how to make that work with .net scripts.
			m_scriptCode.AppendSourceText(script);
			if (m_engine.IsRunning)
			{
				m_engine.Reset();
				m_engine.Compile();
				m_engine.Run();
			}
		}

		public object createObject(string factory)
		{
			// TODO:  Add VsaScriptEnvironment.createObject implementation
			return null;
		}

		public object invokeScriptFunction(string functionName, params object[] functionParams)
		{
			object[] realParams = new object[2 + functionParams.Length];
			realParams[0] = null;
			realParams[1] = m_engine;
			for(int p = 0; p < functionParams.Length; ++p)
				realParams[2+p] = functionParams[p];
			string typeName = "JScript 0"; //m_engine.RootNamespace + ".scriptcode"
			//string typeName = m_engine.RootNamespace + ".scriptcode";
			Type t = m_engine.Assembly.GetType(typeName, true, false);
			MethodInfo m = t.GetMethod(functionName);
			return m.Invoke(null, realParams);

		}

		public bool isScriptFunctionDefined(string functionName)
		{
			string typeName = "JScript 0"; //m_engine.RootNamespace + ".scriptcode"
			Type t = m_engine.Assembly.GetType(typeName, true, false);
			MethodInfo m = null;
			try{m=t.GetMethod(functionName);}catch(Exception){}
			return m != null;
		}

		#endregion

		#region IVsaSite Members

		public object GetEventSourceInstance(string itemName, string eventSourceName)
		{
			// TODO:  Add VsaScriptEnvironment.GetEventSourceInstance implementation
			return null;
		}

		public object GetGlobalInstance(string name)
		{
			// TODO:  Add VsaScriptEnvironment.GetGlobalInstance implementation
			return null;
		}

		public void Notify(string notify, object info)
		{
			// TODO:  Add VsaScriptEnvironment.Notify implementation
		}

		public bool OnCompilerError(IVsaError error)
		{
			Application.currentApp.Log.write(String.Format("Script compile error:{0}", error.ToString()));
			Application.currentApp.Log.write(m_scriptCode.SourceText);
			return false;
		}

		public void GetCompiledState(out byte[] pe, out byte[] debugInfo)
		{
			// TODO:  Add VsaScriptEnvironment.GetCompiledState implementation
			pe = null;
			debugInfo = null;
		}

		#endregion
	}
}
